package data

import (
	"fmt"
	"gorm.io/driver/mysql"
	"gorm_transaction/internal/conf"
	"gorm_transaction/pkg"
	"time"

	"errors"
	clickhouse_v2 "github.com/ClickHouse/clickhouse-go/v2"
	"github.com/go-kratos/kratos/v2/log"
	"github.com/google/wire"
	gorm_ck_driver "gorm.io/driver/clickhouse"
	"gorm.io/gorm"
	"gorm.io/plugin/opentelemetry/tracing"
)

// ProviderSet is data providers.
var ProviderSet = wire.NewSet(NewData, NewAmount1Repo, NewMysql, NewTransaction, NewCellRepo, NewClickhouse, NewStaffRepo)

// Data .
type Data struct {
	Mysql *gorm.DB
	CK    *gorm.DB
}

// NewData .
func NewData(c *conf.Data, mysqlDB, CK *gorm.DB, logger log.Logger) (*Data, func(), error) {
	cleanup := func() {
		log.NewHelper(logger).Info("closing the data resources")
	}
	return &Data{
		Mysql: mysqlDB,
		CK:    CK,
	}, cleanup, nil
}

func NewMysql(c *conf.Data, logger log.Logger) *gorm.DB {
	// recover
	defer func() {
		if err := recover(); err != nil {
			log.NewHelper(logger).Errorw("kind", "mysql", "error", err)
		}
	}()

	// zapLog
	zapLog := pkg.NewZapGormLogV2(log.NewHelper(logger), "polarDB")
	gormConfig := &gorm.Config{
		Logger: zapLog,
	}
	// mysql数据库连接
	db, err := gorm.Open(mysql.Open(c.Database.Source), gormConfig)
	if err != nil {
		panic(err)
	}

	// trace
	errTracing := db.Use(tracing.NewPlugin())
	if errTracing != nil {
		panic(fmt.Sprintf("db.Use-tracing.NewPlugin()失败! err: %v", errTracing))
	}

	sqlDB, err := db.DB()
	if err != nil {
		panic(err)
	}

	// 连接池参数设置
	sqlDB.SetMaxIdleConns(int(c.Database.MinIdleConns))
	sqlDB.SetMaxOpenConns(int(c.Database.MaxOpenConns))
	sqlDB.SetConnMaxLifetime(time.Hour * time.Duration(c.Database.ConMaxLeftTime))

	return db
}

func NewClickhouse(c *conf.Data_Clickhouse, logger log.Logger) *gorm.DB {
	conn := clickhouse_v2.OpenDB(&clickhouse_v2.Options{
		Addr: []string{c.Addr},
		Auth: clickhouse_v2.Auth{
			Database: c.Database,
			Username: c.Username,
			Password: c.Password,
		},
	})

	conn.SetMaxIdleConns(5)
	conn.SetMaxOpenConns(10)
	conn.SetConnMaxLifetime(time.Hour)

	db, err := gorm.Open(gorm_ck_driver.New(gorm_ck_driver.Config{
		Conn:                      conn,
		DisableDatetimePrecision:  true,     // disable datetime64 precision, not supported before clickhouse 20.4
		DontSupportRenameColumn:   true,     // rename column not supported before clickhouse 20.4
		SkipInitializeWithVersion: false,    // smart configure based on used version
		DefaultGranularity:        3,        // 1 granule = 8192 rows
		DefaultCompression:        "LZ4",    // default compression algorithm. LZ4 is lossless
		DefaultIndexType:          "minmax", // index stores extremes of the expression
		DefaultTableEngineOpts:    "ENGINE=MergeTree() ORDER BY tuple()",
	}), &gorm.Config{
		// plugin
		Logger: pkg.NewZapGormLogV2(log.NewHelper(logger), "clickhouse"),
	})
	if err != nil {
		panic(err)
	}
	// tracing
	err = db.Use(tracing.NewPlugin())
	if err != nil {
		panic(errors.New(fmt.Sprintln("db.Use(&pkg.TracePlugin{})", err.Error())))
	}

	log.NewHelper(logger).Infow("kind", "clickhouse", "status", "enable")
	return db
}
